/* PARI source code By R. J. Cano, Sep 19..27 2015 (https://oeis.org/wiki/File:Sol_nymphomathorg_defi_turing_problem_125.txt)
   
   Routines for solving problems related to the challenge issued at:
   
   http://www.nymphomath.ch/turing/probleme.php?id=125
   
   Note: The successful execution of this script might require
         to allocate previously a substantial amount of memory.
         for details about the runtime environment setup, please
         refer to the GP Calculator documentation.
*/

/* Global behavior control parameters ; please keep it as part of this source code or any modification. -- Begin */
FULL=0; 
TOTALS=0;
/* Global behavior control parameters ; please keep it as part of this source code or any modification. -- End */

operator(operand1,operand2)={return(if(TOTALS,operand1<=operand2,operand1==operand2))}

newPool(depth=100,height=100,width=100)=vector(depth+2,k,matrix(height+2,width+2,i,j,-1)); /* Constructor. By default builds a Pool of 100x100x100 */

nextLayer3D(Pool,full=FULL)={ /* a.k.a "Der robot 3D" */
  
  my(d=-1,R=Pool);
  
  for(i=1,#R,forvec(J=[[1,#R[1][,1]],[1,#R[1][1,]]],if((R[i][J[1],J[2]]!=-1)&&(R[i][J[1],J[2]]+1>d),d=1+R[i][J[1],J[2]])));
  
  /* The 26 adjacent positions in 3D */
  for(i=2,#R-1,
    forvec(J=[[2,-1+#R[1][,1]-1],[2,-1+#R[1][1,]]],
      if(R[i][J[1],J[2]]==d-1,
      /* 3D adjacent -- part i:   Only changes a coordinate. */
        if(R[i][J[1],J[2]+1]==-1,R[i][J[1],J[2]+1]=d);
        if(R[i][J[1],J[2]-1]==-1,R[i][J[1],J[2]-1]=d);
        if(R[i][J[1]+1,J[2]]==-1,R[i][J[1]+1,J[2]]=d);
        if(R[i][J[1]-1,J[2]]==-1,R[i][J[1]-1,J[2]]=d);
        if(R[i+1][J[1],J[2]]==-1,R[i+1][J[1],J[2]]=d);
        if(R[i-1][J[1],J[2]]==-1,R[i-1][J[1],J[2]]=d);
        if(full,
        /* 3D adjacent -- part ii:  Only Two coordinates change. */
          if(R[i][J[1]+1,J[2]+1]==-1,R[i][J[1]+1,J[2]+1]=d);
          if(R[i][J[1]+1,J[2]-1]==-1,R[i][J[1]+1,J[2]-1]=d);
          if(R[i][J[1]-1,J[2]+1]==-1,R[i][J[1]-1,J[2]+1]=d);
          if(R[i][J[1]-1,J[2]-1]==-1,R[i][J[1]-1,J[2]-1]=d);
          if(R[i+1][J[1],J[2]+1]==-1,R[i+1][J[1],J[2]+1]=d);
          if(R[i+1][J[1],J[2]-1]==-1,R[i+1][J[1],J[2]-1]=d);
          if(R[i-1][J[1],J[2]+1]==-1,R[i-1][J[1],J[2]+1]=d);
          if(R[i-1][J[1],J[2]-1]==-1,R[i-1][J[1],J[2]-1]=d);
          if(R[i-1][J[1]+1,J[2]]==-1,R[i-1][J[1]+1,J[2]]=d);
          if(R[i-1][J[1]-1,J[2]]==-1,R[i-1][J[1]-1,J[2]]=d);
          if(R[i+1][J[1]+1,J[2]]==-1,R[i+1][J[1]+1,J[2]]=d);
          if(R[i+1][J[1]-1,J[2]]==-1,R[i+1][J[1]-1,J[2]]=d);
        /* 3D adjacent -- part iii: The three coordinates change. */
          if(R[i+1][J[1]+1,J[2]+1]==-1,R[i+1][J[1]+1,J[2]+1]=d);
          if(R[i+1][J[1]+1,J[2]-1]==-1,R[i+1][J[1]+1,J[2]-1]=d);
          if(R[i+1][J[1]-1,J[2]+1]==-1,R[i+1][J[1]-1,J[2]+1]=d);
          if(R[i+1][J[1]-1,J[2]-1]==-1,R[i+1][J[1]-1,J[2]-1]=d);
          if(R[i-1][J[1]+1,J[2]+1]==-1,R[i-1][J[1]+1,J[2]+1]=d);
          if(R[i-1][J[1]+1,J[2]-1]==-1,R[i-1][J[1]+1,J[2]-1]=d);
          if(R[i-1][J[1]-1,J[2]+1]==-1,R[i-1][J[1]-1,J[2]+1]=d);
          if(R[i-1][J[1]-1,J[2]-1]==-1,R[i-1][J[1]-1,J[2]-1]=d);
        )
      )
    )
  );
  R
}

countLayer3D(z,R)={
  my(s=0);
  for(i=1,#R,forvec(J=[[1,#R[1][,1]],[1,#R[1][1,]]],if((R[i][J[1],J[2]]>=0)&&operator(R[i][J[1],J[2]],z),s++)));
  if(!z,s,s-(!!TOTALS)*countLayer3D(0,R))
};

/* Centers a rectangle parallelepiped with sizes (depth,height,width)=(a,b,c) inside
 * an empty pool with the same sizes of "Pool".
*/
getParallelepiped(a,b,c,Pool)={
  my(R=newPool(#Pool,#Pool[1][,1],#Pool[1][1,]));
  if(!!(a*b*c),
    my(q10=(#R-a)\2);
    my(q11=q10+a-1);
    my(q20=(#R[1][,1]-b)\2);
    my(q21=q20+b-1);
    my(q30=(#R[1][1,]-c)\2);
    my(q31=q30+c-1);
    forvec(J=[[q10,q11],[q20,q21],[q30,q31]],R[J[1]][J[2],J[3]]*=0);
  );
  R
}

/* Aid to identify sequences related in 3D to the difference in required blocks between avoiding or not the diagonals. */
lookUpSeq(x,y,z,l,a=1,d=50,h=50,w=50)={my(v0,v1);FULL=1;v1=demo3D(x,y,z,l,d,h,w);FULL=0;v0=demo3D(x,y,z,l,d,h,w);(v1-v0)/a}

/* At purpose of limitations. */
/* Remember!!!, wrong results would be reported if the pool is too small for the sizes of the 3D object and the layers we want to apply. */
/* This script should be trusted as good as temporarily an aid tool for deducing failsafe general formulas. */

demo3D(x,y,z,L,d=20,h=20,w=20)={my(obj3D=getParallelepiped(x,y,z,newPool(d,h,w)),v=vector(L+1));for(k=1,L,obj3D=nextLayer3D(obj3D));for(j=0,L,v[j+1]=countLayer3D(j,obj3D));v}

/* =======================================================*/
/* All the remaining code following below is 2D specific. */
/* =======================================================*/

requiredBlocksPerAppliedLayers(v,n,full=FULL)={
  if((#v==2)&&(v[1]>0)&&(v[2]>0),
    if(n<=0,return(0));
    my(A=2+vecsum(v),B=2*(vecsum(v)+(!!full)*n*(n+1)),Z);
    my(C=A%2);
    if(n==1,return(B));
    A-=C;
    A/=2;
    Z=A+n-2;
    return(B+2*(Z-A+1)*(Z+A+C))
    ,
    return(-1) /* Error. The given vector "v" doesn't represent a rectangle.
                         It must contain only two positive integers */
  )
}

/*
    Note: The following code calls this routine once by defined vector.
          It was a last hour addition. All the remaining code actually
          made it possible to have found finally available something
          like requiredBlocksPerAppliedLayers();
          
          The author hopes this will be possible also for the
          3D original version.
 */


/* VecDiff() was borrowed from the same author, Sep 23 2014  (Yes!, written exactly one year ago... )*/
vecDiff(v,k=1)={my(w=vector(#v-k,j,((-1)^(k%2))*sum(i=0,k,((-1)^(i%2))*binomial(k,i)*v[j+i])));if(type(v)==type(w),w,w~)}

/* The 2D enhanced problem:
  
   Now we have restricted our attention inside a board with
   empty places available to place 1x1 rectangles (small squares).
   
   This is achieved by using matrices.
   
   A shape consisting in a board with some places filled by 1x1 rectangles
   is the object we must surround.
   
   The convention is to represent with zeros the initial state of the board
   and its shape before applying the layers (couchess). Those empty places
   available to work are set to -1;
   
   Each layer application fills some places by setting them to the number of
   the current layer. By doing the things in such way, the same board will contain
   the original shape (as zeros) and every applied layer.
   
   The implemented algorithm is quite simple: To surround each square of the shape
   or a previous layer like if it were isolated. Therefore we only have in 2D four
   directions where to move and check if we need to fill a place there.
   
   Important: Diagonals moves are not necessary in order to achieve the goal
              let us say "hiding all its visible faces". Such is the key fact.
              
   These simple specifications are directly extensible to 3D shapes, and then
   the board becomes a pool. Instead 1x1 rectangles or squares we would have
   1x1x1 parallelepiped or cubes. And instead the 4 directions to move corresponding
   to those sides in a rectangle that might be exposed, now for 3D we would have
   6 different directions corresponding to the six faces of a rectangle parallelepiped
   that might be exposed. So simple.
   
   By using this kind of representation/convention, it might be possible to deduce
   direct/general formulas in order to answer questions about these interesting matters.

   Some implementation details:
   
   Board overflows are avoided. The extra cols and rows for the matrix representing a board
   have to do with this. This mean that a shape is surrounded only if it is possible.
   
   There is a limit for the layers that can be applied. Beyond that, a board will remain
   unchanged.
   
   If a rectangle cannot be drawn, the answer is the reference board, unchanged.
   
   (A rectangle might not be drawn due wrong combinations of position and size, or
    also due other shapes are already present as obstacles inside its assigned area)
 
 */

nextLayer(M:matrix,full=FULL)={ /* a.k.a "Le petit robot" */
  
  my(d=-1,R:matrix);
  
  R=M;
  
  for(x=2,#R[1,]-1,for(y=2,#R[,1]-1,if((R[y,x]!=-1)&&(R[y,x]+1>d),d=R[y,x]+1)));
  
  for(x=2,#R[1,]-1,
    for(y=2,#R[,1]-1,
      
      if( (R[y,x]==d-1),

        if( (R[y,x+1]==-1) , R[y,x+1]=d );        /* Remember: y+0=y */
        if( (R[y+1,x]==-1) , R[y+1,x]=d );        /* Therefore there are these 3 bits: */
        if( (R[y,x-1]==-1) , R[y,x-1]=d );        /*    Either "x" or "y"       (1 bit) */
        if( (R[y-1,x]==-1) , R[y-1,x]=d );        /*    Either "+" or "-"       (1 bit) */
        if(!!full,                                /*    Either zero or the unit (1 bit) */
          if( (R[y+1,x+1]==-1) , R[y+1,x+1]=d );  /*    For 3D or higher the first is no longer a bit */
          if( (R[y+1,x-1]==-1) , R[y+1,x-1]=d );  /*    Finally we conclude that 4*alpha are the conditions */
          if( (R[y-1,x+1]==-1) , R[y-1,x+1]=d );  /*    to test, where alpha is the number of dimensions. */
          if( (R[y-1,x-1]==-1) , R[y-1,x-1]=d );
        );                                        /* Quick test: By alpha=1 meaning to move over a straight line, */
      )                                           /* to "add zero" or "subtract zero" is simplified to "don't move" */
                                                  /* so for 1D we have naturally these three possibilities:  */
    )                                             /* i) Do not move ii) Move to left 1 step iii) Move to right 1 step. */
  );
  
  R
};               /* Such explanation looks logic and reasonably fine, but is wrong. Is not precisely the proper explanation. 
                    it is not cold, just warm.
                    
  Proper explanation is:
  
     In 2D you have two axis, 2 directions and 2 orientations, But if you are about to move from your current position,
     then a third choice must be included, consisting in keeping your current position (do not move). Since you need 2
     coordinates in order to give the precise location of an object relative to a fixed point in the plane, then there
     are two trinary digits (-1, 0, +1) representing the next move you could take, this gives 3^2=9 possibles outcomes
     for the experiment of taking 1 step to move randomly... If you exclude the double zero meaning to stay here (do not move),
     8 ways to move left, 4 of them are diagonals. For 3D since you need now three coordinates, you'll have 3^3-1= 26 ways, being
     20 of them 3D diagonals.

     For N dimensions you'll have 3^N-1 positions where to move and 3^N-2*N-1 diagonals.
     
                    */

countLayer(z,R:matrix)={
  
  my(s=0);
  
  for(x=2,#R[1,]-1,for(y=2,#R[,1]-1,if((R[y,x]>=0)&&operator(R[y,x],z),s++)));
  
  if(!z,s,s-(!!TOTALS)*countLayer(0,R));
  
};

show(R)={
  
  my(d=-1,c=countLayer(0,R),cc=(#R[,1]-2)*(#R[1,]-2));
  
  for(x=2,#R[1,]-1,for(y=2,#R[,1]-1,if((R[y,x]!=-1)&&(R[y,x]+1>d),d=R[y,x]+1)));
  
  /* * /
  my(w=vector(max(d,1)),t);
  / * */
  
  /* */
  my(w=vector(max(d-1,1)));
  /* */
  
  print1("\n\t");for(y=2,#R[,1]-1,for(x=2,#R[1,]-1,if(R[y,x]==-1,print1("."),if(R[y,x]<10,print1(R[y,x]),print1("#"))));print1("\n\t"));
  
  print1("\n\tBoard: ",#R[,1]-2,"x",#R[1,]-2," (",cc," = ",cc-c," available places (dots) + ",c," to surround (zeros))\n\tCounting: ",(d-1>0)*(d-1)," Layer(s).\n\t");if(d-1>0,print1("Blocks per layer:\n\t");print1("["));for(j=1,d-1,w[j/*+1*/]=countLayer(j,R);print1(w[j/*+1*/],if(j+1<d,",","]"))); print("\n");

  if(d-1>0,
    /*
    t=w[1];
    for(k=1,#w,t=gcd(t,w[k]));
    w=vecDiff(w)/t;
    w[1]=t;
    w
  ,
    0
    */
    w
  );
  
};

drawRectangle(upperLeft_y,upperLeft_x,height,width,value,where:matrix)={
  
  my(answer:matrix,pass=1);
  
  if((upperLeft_y+height-1<=#where[,1]-2)&&(upperLeft_x+width-1<=#where[1,]-2),
    for(y=1+upperLeft_y,upperLeft_y+height,if(!pass,break);for(x=1+upperLeft_x,upperLeft_x+width,if(!pass,break);pass*=(where[y,x]==-1)));
    if(pass,
      answer=where;
      for(y=1+upperLeft_y,upperLeft_y+height,for(x=1+upperLeft_x,upperLeft_x+width,answer[y,x]=value));
    );

  );
  
  
  answer
}

demo(R0:matrix,n)={
  
  my(R:matrix);
  
  R=R0;  
  for(i=1,n,R=nextLayer(R));
  
  show(R)

}


/*
   If the board R were enough small, then the following comparison could fail since
   requiredBlocksPerAppliedLayers() is an ideal count where it is assumed that there
   is enough space to surround the object completely by applying all the L layers,
   while nextLayer() only surrounds an object if possible inside the given board.
   
   However: It should be always possible to define a bigger board R where the same
   comparison returns 1 (true).
*/

compareFor(v,L,R)={demo(drawRectangle((#R[,1]-v[1])\2,(#R[1,]-v[2])\2,v[1],v[2],0,R),L)==vector(L,k,requiredBlocksPerAppliedLayers(v,k))};

/* === Defining the board === */

/* WARNING: Always define your board as a matrix with two extra rows and two extra cols, relative to the original sizes you would wish to set. */

A=matrix(32,52,i,j,-1); /* "A", A work board: A matrix filled with -1 */

/* WARNING: Always define your board as a matrix with two extra rows and two extra cols, relative to the original sizes you would wish to set. (Deja-vu this!) */

/* The following 4 assignations defines an arbitrary shape represented on our board "A" */

A=matrix(32,52,i,j,-1); /* Reset to an empty board 30 rows x 50 cols */

/* * / A=drawRectangle(15,25,1,1,0,A); / * */

/* B stores a copy of A over which a layer is applied. */
B=nextLayer(drawRectangle(5,5,4,4,0,A));

/* Suggestions for the user... */
print("\n\n\tType either \"show(A);\" or \"show(B);\", \n\t or \"compareFor([1,1],3,A)\" or \"demo3D(1,2,3,5)\"\n\tOr yet try \"lookUpSeq(1,1,1,10)\" in order to find first 10 terms \n\tof A195322 prepended by a zero and hit Enter...\n\n\t\t(And please study the sourcecode)\n");

/* From here onwards, the user is free to experience this matters by his/her own means and inspiration. */

/* For example you could try also instructions like this:
  
   demo(drawRectangle(15,15,1,1,0,matrix(30,30,i,j,-1)),10)
   
*/ 

/* ---> End <--- */






























/* "draft" Surprise: A gift art for our dear friends. */

draft=matrix(32,52,i,j,-1);
draft[6,9]=0;
draft[6,10]=0;
draft[6,11]=0;
draft[6,12]=0;
draft[6,13]=0;
draft[6,14]=0;
draft[6,15]=0;
draft[6,16]=0;
draft[6,35]=0;
draft[6,36]=0;
draft[6,41]=0;
draft[6,42]=0;
draft[7,9]=0;
draft[7,10]=0;
draft[7,15]=0;
draft[7,16]=0;
draft[7,35]=0;
draft[7,36]=0;
draft[7,41]=0;
draft[7,42]=0;
draft[8,9]=0;
draft[8,10]=0;
draft[8,15]=0;
draft[8,16]=0;
draft[9,9]=0;
draft[9,10]=0;
draft[9,15]=0;
draft[9,16]=0;
draft[9,32]=0;
draft[9,33]=0;
draft[9,45]=0;
draft[9,46]=0;
draft[10,9]=0;
draft[10,10]=0;
draft[10,15]=0;
draft[10,16]=0;
draft[10,33]=0;
draft[10,34]=0;
draft[10,44]=0;
draft[10,45]=0;
draft[11,9]=0;
draft[11,10]=0;
draft[11,11]=0;
draft[11,12]=0;
draft[11,13]=0;
draft[11,14]=0;
draft[11,15]=0;
draft[11,16]=0;
draft[11,35]=0;
draft[11,36]=0;
draft[11,37]=0;
draft[11,38]=0;
draft[11,39]=0;
draft[11,40]=0;
draft[11,41]=0;
draft[11,42]=0;
draft[11,43]=0;
draft[13,17]=0;
draft[13,18]=0;
draft[13,19]=0;
draft[13,20]=0;
draft[13,21]=0;
draft[13,22]=0;
draft[13,23]=0;
draft[13,24]=0;
draft[14,17]=0;
draft[14,18]=0;
draft[15,17]=0;
draft[15,18]=0;
draft[15,19]=0;
draft[15,20]=0;
draft[15,21]=0;
draft[15,22]=0;
draft[15,23]=0;
draft[16,17]=0;
draft[16,18]=0;
draft[17,17]=0;
draft[17,18]=0;
draft[17,26]=0;
draft[17,27]=0;
draft[17,28]=0;
draft[17,29]=0;
draft[17,30]=0;
draft[18,17]=0;
draft[18,18]=0;
draft[18,19]=0;
draft[18,20]=0;
draft[18,21]=0;
draft[18,22]=0;
draft[18,23]=0;
draft[18,27]=0;
draft[18,28]=0;
draft[19,27]=0;
draft[19,28]=0;
draft[20,27]=0;
draft[20,28]=0;
draft[21,27]=0;
draft[21,28]=0;
draft[22,25]=0;
draft[22,26]=0;
draft[22,27]=0;
draft[22,28]=0;
draft[22,29]=0;
draft[22,30]=0;
draft[22,35]=0;
draft[22,36]=0;
draft[22,37]=0;
draft[22,38]=0;
draft[22,39]=0;
draft[23,34]=0;
draft[23,35]=0;
draft[24,34]=0;
draft[24,35]=0;
draft[25,34]=0;
draft[25,35]=0;
draft[25,36]=0;
draft[25,37]=0;
draft[25,38]=0;
draft[25,39]=0;
draft[25,40]=0;
draft[26,39]=0;
draft[26,40]=0;
draft[27,39]=0;
draft[27,40]=0;
draft[28,34]=0;
draft[28,35]=0;
draft[28,36]=0;
draft[28,37]=0;
draft[28,38]=0;
draft[28,39]=0;